import asyncio
import time


async def a():
    print('Suspending a')
    await asyncio.sleep(3)
    print('Resuming a')
    return 'A'


async def b():
    print('Suspending b')
    await asyncio.sleep(1)
    print('Resuming b')
    return 'B'


async def test():
    # asyncio.gather封装的Task全程黑盒，只告诉你协程结果
    # return_value_a, return_value_b = await asyncio.gather(a(), b())
    # print(return_value_a, return_value_b)

    # asyncio.wait会返回封装的Task(包含已完成和挂起的任务)，如果你关注协程执行结果你需要从对应Task实例里面用result方法自己拿
    done, pending = await asyncio.wait([a(), b()])
    print(done)
    print(pending)
    # list(done)[0].add_done_callback()
    list(done)[0].cancel()
    print(list(done)[0].result())
    print(list(done)[1].result())

    # asyncio.wait支持选择返回的时机,asyncio.wait支持一个接收参数return_when，在默认情况下，asyncio.wait会等待全部任务完成(return_when='ALL_COMPLETED')，它还支持FIRST_COMPLETED（第一个协程完成就返回）和FIRST_EXCEPTION（出现第一个异常就返回）
    done, pending = await asyncio.wait([a(), b()], return_when=asyncio.tasks.FIRST_COMPLETED)
    print('done:', done)
    print('pending:', pending)
    print(list(done)[0].result())
    # 看到了吧，这次只有协程b完成了，协程a还是pending状态。
    # 在大部分情况下，用asyncio.gather是足够的，如果你有特殊需求，可以选择asyncio.wait，举2个例子
    # 1.需要拿到封装好的Task，以便取消或者添加成功回调等
    # 2.业务上需要FIRST_COMPLETED/FIRST_EXCEPTION即返回的


def show_perf(func):
    print('*' * 20)
    start = time.perf_counter()
    asyncio.run(func())
    print(f'{func.__name__} Cost: {time.perf_counter() - start}')


if __name__ == '__main__':
    show_perf(test)
    # done, pending = await asyncio.wait([a(), b()])

    print('完成')
